/**
 * @copyright 2015 Indie Semiconductor.
 *
 * This file is proprietary to Indie Semiconductor.
 * All rights reserved. Reproduction or distribution, in whole
 * or in part, is forbidden except by express written permission
 * of Indie Semiconductor.
 *
 * @file pwm_sfr_access.h
 */
 
#ifndef __PWM_SFR_ACCESS_H__
#define __PWM_SFR_ACCESS_H__

#include <stdint.h>
#include <stdbool.h>
#include "orion.h"

#define E_PWM_PRESCALE_DIV1            0
#define E_PWM_PRESCALE_DIV2            1
#define E_PWM_PRESCALE_DIV4            2
#define E_PWM_PRESCALE_DIV8            3
#define E_PWM_PRESCALE_DIV16           4
#define E_PWM_PRESCALE_DIV64           5
#define E_PWM_PRESCALE_DIV256          6
#define E_PWM_PRESCALE_DIV1024         7

#define PWM_WIDTH_BASE (uint32_t *)&PWM_SFRS->PWIDTH0

/**
 * @brief Set period for PWM
 *
 * @param pwm The enum of PWM driver.
 * @param period The PWM period in clock counts.
 */
static __INLINE void f_PWM_SetPeriod(uint8_t pwm, uint32_t period)
{
    PWM_SFRS->CYCLE.PERIOD = period;
}

/**
 * @brief Set width for PWM
 *
 * @param pwm The enum of PWM driver.
 * @param width The PWM width in clock counts.
 */
static __INLINE void f_PWM_SetWidth(uint8_t pwm, uint32_t width)
{
    *(PWM_WIDTH_BASE + pwm) = width;
}

/**
 * @brief Set clock pre-scaler for PWM
 *
 * @param div The PWM clock divider setting.
 */
static __INLINE void f_PWM_SetPreScaler(uint8_t div)
{
    PWM_SFRS->CYCLE.PRESCL = div;
}

/**
 * @brief Enable on inverter for PWM
 * @param pwm The enum of PWM driver.
 */
static __INLINE void f_PWM_InvertOn(uint8_t pwm)
{
    PWM_SFRS->INVERT |= 1 << pwm;
}

/**
 * @brief Disable on inverter for PWM
 * @param pwm The enum of PWM driver.
 */
static __INLINE void f_PWM_InvertOff(uint8_t pwm)
{
    PWM_SFRS->INVERT &= ~(1 << pwm);
}

/**
 * @brief Enable PWM
 * @param pwm The enum of PWM driver.
 */
static __INLINE void f_PWM_Enable(uint8_t pwm)
{
    PWM_SFRS->ENAREQ |= 1 << pwm;
}

/**
 * @brief Disable PWM
 * @param pwm The enum of PWM driver.
 */
static __INLINE void f_PWM_Disable(uint8_t pwm)
{
    PWM_SFRS->ENAREQ &= ~(1 << pwm);
}

/**
 * @brief Update PWM with new period and width.
 */
static __INLINE void f_PWM_Update(void)
{
    PWM_SFRS->UPDATE = 1;
}

/**
 * @brief Check if PWM update in progress.
 */
static __INLINE uint8_t f_PWM_IsUpdate(void)
{
    return PWM_SFRS->UPDATE;
}

#endif /* __PWM_SFR_ACCESS_H__ */
